package com.jweb.framework.security.data.transform;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.security.MessageDigest;
import java.util.Map;

import javax.crypto.Cipher;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESedeKeySpec;

import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;

import com.jweb.framework.security.pass.Global;
import com.jweb.framework.security.pass.IDecryptPass;

/**
 * 锟睫革拷锟剿ｏ拷 Thomas
 * 锟睫革拷锟斤拷锟捷ｏ拷锟斤拷锟斤拷 
 * 锟斤拷说锟斤拷锟斤拷锟斤拷菘獠匡拷锟斤拷侄渭印锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷取锟斤拷
 */
public class PwdDecryptPass implements IDecryptPass /*, InitializingBean , ApplicationContextAware*/ {
	
	private Cipher encip ;
	private Cipher decip ;
	private Cipher encip1 ;
	private Cipher decip1 ;
	private String desKey ;
	private String dateKey ;
	
	private final String Algorithm = "DESede";
	final byte initKeyBytes[] = { 113, 52, 52, 120, 9, -85, -51, -117, -2, -36,
			-70, -112, -121, 101, 111, 33, -17, -51, -85, 9, 120, 86, 52, 18 };
	
	public String decryptStr(String in){
		try {
			return new String(this.decip.doFinal(asc2bcd(in)));
		} catch (Exception e) {
			e.printStackTrace() ;
		}
		
		return null ;
	}
	
	public String getDePass(JdbcTemplate jdbcTemplate , String securityId) throws FileNotFoundException , IOException , Exception {
		String enPass = getEnPassFromFile(jdbcTemplate , securityId);
		init3DES();
		String dePass = decryptStr(enPass);
		return dePass ;
	}
	
	private boolean init3DES(){
		Global.desKey = "CAB774DCC2FE66612919C274B11GG4D456E6DDC10F6D7E64DC0DB194A3EC6261";
		if(Global.desKey != null){
			this.desKey = Global.desKey ;
		}
		try {
			SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(this.Algorithm);
			DESedeKeySpec desKeySpec1 = new DESedeKeySpec(this.initKeyBytes);
			javax.crypto.SecretKey desKey1 = keyFactory.generateSecret(desKeySpec1);
			this.encip1 = Cipher.getInstance(this.Algorithm);
			this.decip1 = Cipher.getInstance(this.Algorithm);
			this.encip1.init(1, desKey1);
			this.decip1.init(2, desKey1);
			
			byte[] keyBytes = md5Buffer(decrypt1Str(this.dateKey)).getBytes();
			DESedeKeySpec desKeySpec2 = new DESedeKeySpec(keyBytes);
			javax.crypto.SecretKey desKey2 = keyFactory.generateSecret(desKeySpec2);
			this.encip = Cipher.getInstance(this.Algorithm);
			this.decip = Cipher.getInstance(this.Algorithm);
			this.encip.init(1, desKey2);
			this.decip.init(2, desKey2);
			
		} catch (Exception e) {
			e.printStackTrace() ;
			return false ;
		}
		
		return true ;
	}
	
	public String decrypt1Str(String in){
		try {
			return new String(this.decip1.doFinal(asc2bcd(in)));
		} catch (Exception e) {
			e.printStackTrace() ;
		}
		
		return null ;
	}
	
	private String getEnPassFromFile(JdbcTemplate jdbcTemplate , String securityId) throws FileNotFoundException , IOException , Exception {
		String enPass = getPasswd(jdbcTemplate , securityId);
        if(enPass == null){
        	throw new Exception("the request password not found");
        }
        String enPassArr[] = enPass.split(":");
        boolean isMd5Ok = md5StrOk((new StringBuilder(String.valueOf(enPassArr[0]))).append(":").append(enPassArr[1]).toString(), enPassArr[2]);
        if(!isMd5Ok){
        	throw new Exception("the password file is changed.");
        }
        else {
        	this.dateKey = enPassArr[0];
        	return enPassArr[1];
        }
	}
	
	private boolean md5StrOk(String from , String md5) {
		if(md5 == null){
			return false ;
		}
		else {
			return md5Buffer(from).equals(md5);
		}
	}
	
	private String md5Buffer(String strSrc) {
		try {
			MessageDigest md = MessageDigest.getInstance("MD5");
			md.update(strSrc.getBytes());
			return bcd2asc(md.digest());
		} catch (Exception e) {
			e.printStackTrace() ;
		}
		
		return null ;
	}
	
	private String bcd2asc(byte b[]){
		String hs = "";
        String stmp = "";
        for(int n = 0; n < b.length; n++)
        {
            stmp = Integer.toHexString(b[n] & 255);
            if(stmp.length() == 1)
                hs = (new StringBuilder(String.valueOf(hs))).append("0").append(stmp).toString();
            else
                hs = (new StringBuilder(String.valueOf(hs))).append(stmp).toString();
        }

        return hs.toUpperCase();
	}
	
	private String getPasswd(JdbcTemplate jdbcTemplate , String securityId) {
		try {
			Map<String , Object> map = jdbcTemplate.queryForMap("SELECT PASSWD FROM T_EN_RBAC_DATASECURITY WHERE SECURITYID=?", 
														securityId);
			
			return (String) map.get("PASSWD") ;
		} catch (DataAccessException e) {
			e.printStackTrace();
			throw e ;
		}
	}
	
	private byte[] asc2bcd(String hexstr){
		if (hexstr.length() % 2 != 0){
			hexstr = (new StringBuilder(String.valueOf(hexstr))).append("0").toString();
		}
		byte bytes[] = new byte[hexstr.length() / 2];
		for (int i = 0; i < hexstr.length() / 2; i++) {
			byte temp[] = new byte[2];
			temp[0] = (byte) hexstr.charAt(i * 2);
			temp[1] = (byte) hexstr.charAt(i * 2 + 1);
			bytes[i] = (byte) Integer.parseInt(new String(temp), 16);
		}

		return bytes;
	}

	@Override
	public String getDePass(String hostIp, String accName)
			throws FileNotFoundException, IOException, Exception {
		throw new UnsupportedOperationException() ;
	}
}
